package service

import (
	"fmt"
	"net"
	"os"

	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"gopkg.in/natefinch/lumberjack.v2"
)

func initLog() (log *zap.Logger) {
	var infoWriteSyncer zapcore.WriteSyncer
	var errorWriteSyncer zapcore.WriteSyncer
	var coreArr []zapcore.Core

	// 普通日志分割
	infoHook := lumberjack.Logger{
		Filename:   Conf.Log.Path + Conf.App.Name + "_info.log", // 日志文件路径
		MaxSize:    128,                                         // 每个日志文件保存的最大尺寸 单位：UserClientM
		MaxBackups: 30,                                          // 日志文件最多保存多少个备份
		MaxAge:     7,                                           // 文件最多保存多少天
		Compress:   true,                                        // 是否压缩
	}

	// 错误日志分割
	errorHook := lumberjack.Logger{
		Filename:   Conf.Log.Path + Conf.App.Name + "_error.log",
		MaxSize:    128,
		MaxBackups: 30,
		MaxAge:     7,
		Compress:   true,
	}

	// zap配置
	encoderConfig := zapcore.EncoderConfig{
		TimeKey:        "time",       // 时间戳字段
		LevelKey:       "level",      // 日志等级字段
		NameKey:        "logger",     // 名称字段
		CallerKey:      "linenum",    // 调用行Key
		MessageKey:     "msg",        // 消息体Key
		StacktraceKey:  "stacktrace", // 堆栈信息Key
		LineEnding:     zapcore.DefaultLineEnding,
		EncodeLevel:    zapcore.LowercaseLevelEncoder,  // 小写编码器
		EncodeTime:     zapcore.ISO8601TimeEncoder,     // ISO8601 UTC 时间格式
		EncodeDuration: zapcore.SecondsDurationEncoder, //
		EncodeCaller:   zapcore.FullCallerEncoder,      // 全路径编码s器
		EncodeName:     zapcore.FullNameEncoder,
	}

	// encoder配置
	var encoder zapcore.Encoder

	if Conf.Log.Logstash.Addr != "" {
		encoder = zapcore.NewJSONEncoder(encoderConfig)
	} else {
		encoder = zapcore.NewConsoleEncoder(encoderConfig)
	}

	// 设置输出(根据环境)
	switch Conf.App.Env {
	case "prod":

		// logstash 日志打印
		if Conf.Log.Logstash.Addr != "" {
			logstashConn, err := net.Dial("tcp", Conf.Log.Logstash.Addr)
			if err != nil {
				panic(fmt.Sprintf("logstash 连接失败: %s\n", err.Error()))

			} else {
				infoWriteSyncer = zapcore.NewMultiWriteSyncer(zapcore.AddSync(&infoHook), zapcore.AddSync(logstashConn)) // 打印到控制台和文件
				errorWriteSyncer = zapcore.NewMultiWriteSyncer(zapcore.AddSync(&errorHook), zapcore.AddSync(logstashConn))
			}
		} else {
			infoWriteSyncer = zapcore.NewMultiWriteSyncer(zapcore.AddSync(&infoHook)) // 打印到控制台和文件
			errorWriteSyncer = zapcore.NewMultiWriteSyncer(zapcore.AddSync(&errorHook))
		}

	default:
		// 默认仅仅打印只控制台
		infoWriteSyncer = zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout))
		errorWriteSyncer = zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout))
	}

	// 设置日志级别
	highPriority := zap.LevelEnablerFunc(func(lev zapcore.Level) bool { // error级别
		return lev >= zap.ErrorLevel
	})
	lowPriority := zap.LevelEnablerFunc(func(lev zapcore.Level) bool { // info和debug级别,debug级别是最低的
		return lev < zap.ErrorLevel && lev >= zap.DebugLevel
	})

	// 设置核心配置
	infoCore := zapcore.NewCore(
		encoder, // 编码器配置
		infoWriteSyncer,
		lowPriority, // 日志级别
	)
	errorCore := zapcore.NewCore(
		encoder, // 编码器配置
		errorWriteSyncer,
		highPriority, // 日志级别
	)
	coreArr = append(coreArr, infoCore)
	coreArr = append(coreArr, errorCore)

	// 开启开发模式，堆栈跟踪
	caller := zap.AddCaller()

	// 设置初始化字段
	filed := zap.Fields(zap.String("app_name", Conf.App.Name))

	// 构造日志(多日志配置)
	log = zap.New(zapcore.NewTee(coreArr...), caller, filed)

	return
}
